package cn.justforchris.system.service.impl;


import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.justforchris.exception.BusinessException;
import cn.justforchris.jwt.JwtUtil;
import cn.justforchris.jwt.Payload;
import cn.justforchris.system.domain.Logininfo;
import cn.justforchris.system.domain.Menu;
import cn.justforchris.system.dto.LoginDto;
import cn.justforchris.system.mapper.LogininfoMapper;
import cn.justforchris.system.query.LogininfoQuery;
import cn.justforchris.system.service.ILogininfoService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
@Slf4j
@Transactional(readOnly = true,propagation = Propagation.SUPPORTS)
public class LogininfoServiceImpl implements ILogininfoService {

    @Autowired
    private LogininfoMapper logininfoMapper;

    @Override
    @Transactional
    public void insertLogininfo(Logininfo logininfo) {
        logininfoMapper.insertLogininfo(logininfo);

    }

    @Override
    @Transactional
    public void deleteLogininfo(Long id) {
        logininfoMapper.deleteLogininfo(id);
    }

    @Override
    public void patchDelete(Long[] ids) {
        logininfoMapper.patchDelete(ids);
    }

    @Override
    @Transactional
    public void updateLogininfo(Logininfo logininfo) {
        logininfoMapper.updateLogininfo(logininfo);
    }

    @Override
    public Logininfo getLogininfoById(Long id) {
        return logininfoMapper.getLogininfoById(id);
    }

    @Override
    public List<Logininfo> getAll() {
        return logininfoMapper.getAll();
    }

    @Override
    public PageInfo<Logininfo> queryPage(LogininfoQuery queryPage) {
        PageHelper.startPage(queryPage.getCurrentPage(),queryPage.getPageSize());
        List<Logininfo> data = logininfoMapper.queryPage(queryPage);
        /*
        这里获取到的是符合传入参数currentpage和pagesize的数据,也就是说,如果不传pagesize就只有五条因为怕个size如果不传入的话就是5
        但是如果有pagesize传入就根据传入数据来
        */
        return new PageInfo<>(data);
        /*这里面就包含了pagehelper帮忙计算出来的total(总共多少条,和根据分页提取出的数据)*/

    }

    @Override
    public String accountLogin(LoginDto loginDto) {

        String account = loginDto.getAccount();

        String password = loginDto.getPassword();
        Integer type = loginDto.getType();
        //业务:
           // 1.校验 用户名或密码是否为空
             if(StrUtil.isBlank(account)|| StrUtil.isBlank(password)){
                throw new BusinessException("账号或密码为空");
             }
            //2.校验 用户名是否存在(是否在数据库中)
            Logininfo logininfo = logininfoMapper.findByUsername(account);
             if (logininfo==null){
                 throw new BusinessException("账号错误");
             }
            //3.校验 密码是否正确(是否和数据库中的密码匹配)
            String password1 = logininfo.getPassword();

            String salt = logininfo.getSalt();
            //获取数据库储存的盐值
            String afterMd5Pwd = SecureUtil.md5(password + salt);
            if ( !StrUtil.equals(password1,afterMd5Pwd)){
                throw new BusinessException("密码错误");
            }
            //4.校验 是否禁用(是否被禁用disable的值)
            if(!logininfo.getDisable()){
                throw new BusinessException("账号已被禁用,请联系管理员处理");
            }
            /*5.如果都通过了,判断是什么账户(用户账户还是管理员账户,由type的值判断),如果是用户
              则只生成token并返回,如果是管理员则返回token和用户信息(用户信息包括权限和菜单)
            */
        Payload payload = new Payload();
        /*校验已经通过了,为了用户的信息安全,所以将密码和盐值置空,因为已经通过校验了所以这两个数据不重要了*/
        logininfo.setPassword(null);
        logininfo.setSalt(null);
        payload.setLogininfo(logininfo);
        if(type==0) {
                //管理员账户
//            List<Menu> menus = logininfoMapper.getMenusById(logininfo.getId());
            List<Menu> menus = typeTree(logininfo.getId());
            List<String> permissions = logininfoMapper.getPermissions(logininfo.getId());
            payload.setMenus(menus);
            payload.setPermissions(permissions);

            }else {
                throw new BusinessException("账户有未知问题,请联系管理员处理");
            }
        String token = JwtUtil.generateToken(payload);
        return token;
    }

    private List<Menu> typeTree(Long id) {
        /*第一步,获取所有的数据对象*/
        List<Menu> types = logininfoMapper.getMenusById(id);
        /*为了提高效率并且,容易获取到父类型对象,所以创建一个map集合用来存放id和对象*/
        Map<Long,Menu> map = new HashMap<>();
        /*循环获取到的数据对象,将对象放入map集合中*/
        for (Menu type : types) {
            map.put(type.getId(),type);
        }
        /*第三步,创建一个集合用于存放父类型数据对象*/
        List<Menu> typeTree = new ArrayList<>();
        /*遍历集合types判断是否有父类型,如果没有就将当前对象放入集合中*/
        for (Menu type : types) {
            if (type.getParentId()==null){
                typeTree.add(type);
            }else {
                /*如果有父类型,就通过父类型id获取到父类型对象,然后将当前对象放入父类型对象的children集合中*/
                /*不过,为了避免空指针异常,需要判断父类型是否存在*/
                Menu parentType = map.get(type.getParentId());
                if (parentType!=null) {
                    List<Menu> children = parentType.getChildren();
                    children.add(type);
                }
            }
        }
        return typeTree;
    }

    public static void main(String[] args) {
        String salt = RandomUtil.randomString(32);
        System.out.println("盐"+salt);
        String password = "123456";

        String afterMd5Pwd = SecureUtil.md5(password + salt);
        System.out.println("密码"+afterMd5Pwd);
    }
    }



